spinlock: Add debug-build checks for IRQ-safe spinlocks.
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 23 Oct 2008 10:53:52 +0000 (11:53 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 23 Oct 2008 10:53:52 +0000 (11:53 +0100)
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/setup.c
xen/common/spinlock.c
xen/include/xen/spinlock.h

index 967014e30185e9165f1f7de7a7d5970124c6bb75..784a833acaf978f7a792d12c6ed53ccf7784db6f 100644 (file)
@@ -1059,6 +1059,8 @@ void __init __start_xen(unsigned long mbi_p)
                         cmdline) != 0)
         panic("Could not set up DOM0 guest OS\n");
 
+    spin_debug_enable();
+
     /* Scrub RAM that is still free and so may go to an unprivileged domain. */
     scrub_heap_pages();
 
index 438e51deb8d1a5f74fb3fd98decd6d866e029ef3..95affbde019427310ad379031ce9aa3988ea3335 100644 (file)
@@ -1,9 +1,48 @@
 #include <xen/config.h>
+#include <xen/irq.h>
 #include <xen/smp.h>
 #include <xen/spinlock.h>
 
+#ifndef NDEBUG
+
+static atomic_t spin_debug __read_mostly = ATOMIC_INIT(0);
+
+static void check_lock(struct lock_debug *debug)
+{
+    int irq_safe = !local_irq_is_enabled();
+
+    if ( unlikely(atomic_read(&spin_debug) <= 0) )
+        return;
+
+    /* A few places take liberties with this. */
+    /* BUG_ON(in_irq() && !irq_safe); */
+
+    if ( unlikely(debug->irq_safe != irq_safe) )
+    {
+        int seen = cmpxchg(&debug->irq_safe, -1, irq_safe);
+        BUG_ON(seen == !irq_safe);
+    }
+}
+
+void spin_debug_enable(void)
+{
+    atomic_inc(&spin_debug);
+}
+
+void spin_debug_disable(void)
+{
+    atomic_dec(&spin_debug);
+}
+
+#else /* defined(NDEBUG) */
+
+#define check_lock(l) ((void)0)
+
+#endif
+
 void _spin_lock(spinlock_t *lock)
 {
+    check_lock(&lock->debug);
     _raw_spin_lock(&lock->raw);
 }
 
@@ -11,6 +50,7 @@ void _spin_lock_irq(spinlock_t *lock)
 {
     ASSERT(local_irq_is_enabled());
     local_irq_disable();
+    check_lock(&lock->debug);
     _raw_spin_lock(&lock->raw);
 }
 
@@ -18,6 +58,7 @@ unsigned long _spin_lock_irqsave(spinlock_t *lock)
 {
     unsigned long flags;
     local_irq_save(flags);
+    check_lock(&lock->debug);
     _raw_spin_lock(&lock->raw);
     return flags;
 }
@@ -41,16 +82,19 @@ void _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
 
 int _spin_is_locked(spinlock_t *lock)
 {
+    check_lock(&lock->debug);
     return _raw_spin_is_locked(&lock->raw);
 }
 
 int _spin_trylock(spinlock_t *lock)
 {
+    check_lock(&lock->debug);
     return _raw_spin_trylock(&lock->raw);
 }
 
 void _spin_barrier(spinlock_t *lock)
 {
+    check_lock(&lock->debug);
     do { mb(); } while ( _raw_spin_is_locked(&lock->raw) );
     mb();
 }
@@ -70,6 +114,8 @@ void _spin_lock_recursive(spinlock_t *lock)
     /* Don't allow overflow of recurse_cpu field. */
     BUILD_BUG_ON(NR_CPUS > 0xfffu);
 
+    check_lock(&lock->debug);
+
     if ( likely(lock->recurse_cpu != cpu) )
     {
         spin_lock(lock);
@@ -92,6 +138,7 @@ void _spin_unlock_recursive(spinlock_t *lock)
 
 void _read_lock(rwlock_t *lock)
 {
+    check_lock(&lock->debug);
     _raw_read_lock(&lock->raw);
 }
 
@@ -99,6 +146,7 @@ void _read_lock_irq(rwlock_t *lock)
 {
     ASSERT(local_irq_is_enabled());
     local_irq_disable();
+    check_lock(&lock->debug);
     _raw_read_lock(&lock->raw);
 }
 
@@ -106,6 +154,7 @@ unsigned long _read_lock_irqsave(rwlock_t *lock)
 {
     unsigned long flags;
     local_irq_save(flags);
+    check_lock(&lock->debug);
     _raw_read_lock(&lock->raw);
     return flags;
 }
@@ -129,6 +178,7 @@ void _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
 
 void _write_lock(rwlock_t *lock)
 {
+    check_lock(&lock->debug);
     _raw_write_lock(&lock->raw);
 }
 
@@ -136,6 +186,7 @@ void _write_lock_irq(rwlock_t *lock)
 {
     ASSERT(local_irq_is_enabled());
     local_irq_disable();
+    check_lock(&lock->debug);
     _raw_write_lock(&lock->raw);
 }
 
@@ -143,6 +194,7 @@ unsigned long _write_lock_irqsave(rwlock_t *lock)
 {
     unsigned long flags;
     local_irq_save(flags);
+    check_lock(&lock->debug);
     _raw_write_lock(&lock->raw);
     return flags;
 }
index c49be63c5f138cdd4ac959543a46761fb8aa4691..fec426459039b4a8dba42b8c1f7f67aa0d4e6757 100644 (file)
@@ -5,21 +5,38 @@
 #include <asm/system.h>
 #include <asm/spinlock.h>
 
+#ifndef NDEBUG
+struct lock_debug {
+    int irq_safe; /* +1: IRQ-safe; 0: not IRQ-safe; -1: don't know yet */
+};
+#define _LOCK_DEBUG { -1 }
+void spin_debug_enable(void);
+void spin_debug_disable(void);
+#else
+struct lock_debug { };
+#define _LOCK_DEBUG { }
+#define spin_debug_enable() ((void)0)
+#define spin_debug_disable() ((void)0)
+#endif
+
 typedef struct {
     raw_spinlock_t raw;
     u16 recurse_cpu:12;
     u16 recurse_cnt:4;
+    struct lock_debug debug;
 } spinlock_t;
 
-#define SPIN_LOCK_UNLOCKED { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0 }
+
+#define SPIN_LOCK_UNLOCKED { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0, _LOCK_DEBUG }
 #define DEFINE_SPINLOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED
 #define spin_lock_init(l) (*(l) = (spinlock_t)SPIN_LOCK_UNLOCKED)
 
 typedef struct {
     raw_rwlock_t raw;
+    struct lock_debug debug;
 } rwlock_t;
 
-#define RW_LOCK_UNLOCKED { _RAW_RW_LOCK_UNLOCKED }
+#define RW_LOCK_UNLOCKED { _RAW_RW_LOCK_UNLOCKED, _LOCK_DEBUG }
 #define DEFINE_RWLOCK(l) rwlock_t l = RW_LOCK_UNLOCKED
 #define rwlock_init(l) (*(l) = (rwlock_t)RW_LOCK_UNLOCKED)